const gulp = require('gulp')
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const tinypng = require('gulp-tinypng-unlimited')
const imagemin = require('gulp-imagemin')
const useref = require('gulp-useref')
const del = require('del')
const browserSync = require('browser-sync')
const pkg = require('./package.json')

// 开发服务器实例
const bs = browserSync.create()

// 各种类型源文件地址
const paths = {
  // 样式文件
  styles: {
    src: 'src/assets/styles/*.scss',
    dest: 'dist',
  },
  // 脚本文件
  scripts: {
    src: 'src/assets/scripts/*.js',
    dest: 'dist',
  },
  // 模板文件
  pages: {
    src: 'src/*.html',
    dest: 'dist',
  },
  // .@(gif|svg)图片文件
  imagemin: {
    //
    src: 'src/assets/images/*.@(gif|svg)',
    dest: 'dist',
  },
  // .@(png|jpg|jpeg)图片文件
  tinypng: {
    src: 'src/assets/images/*.@(png|jpg|jpeg)',
    dest: 'dist',
  },
  // 字体文件
  fonts: {
    src: 'src/assets/fonts/**',
    dest: 'dist',
  },
  // public文件
  public: {
    src: 'public/**',
    dest: 'dist',
  },
  // useref
  useref: {
    src: 'dist/*.html',
    dest: 'dist',
    searchPath: ['dist', '.'],
  },
}

// 模板标签用到的数据
const pagesData = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html',
    },
    {
      name: 'Features',
      link: 'features.html',
    },
    {
      name: 'About',
      link: 'about.html',
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce',
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme',
        },
        {
          name: 'divider',
        },
        {
          name: 'About',
          link: 'https://github.com/zce',
        },
      ],
    },
  ],
  pkg,
  date: new Date(),
}

// 清除任务，需要在编译前执行
function clean() {
  return del(['dist'])
}

// 样式编译
function styles() {
  return gulp
    .src(paths.styles.src, { base: 'src' })
    .pipe(sass())
    .pipe(gulp.dest(paths.styles.dest))
}

// 脚本编译
function scripts() {
  return gulp
    .src(paths.scripts.src, { base: 'src' })
    .pipe(
      babel({
        presets: ['@babel/preset-env'],
      }),
    )
    .pipe(gulp.dest(paths.scripts.dest))
}

// 模板编译
function pages() {
  return gulp
    .src(paths.pages.src, { base: 'src' })
    .pipe(
      swig({
        data: pagesData,
      }),
    )
    .pipe(gulp.dest(paths.pages.dest))
}

// (png|jpg|jpeg)图片编译
function imagesTinypng() {
  return gulp
    .src(paths.tinypng.src, { base: 'src' })
    .pipe(tinypng({
      cache: true, // 开启缓存
      outputErrorLog: true, // 打印错误日志
      outputErrorFiles: false, // 仍然将错误文件输出
    }))
    .pipe(gulp.dest(paths.tinypng.dest))
}

// (gif|svg)图片编译
function imagesImagemin() {
  return gulp
    .src(paths.imagemin.src, { base: 'src' })
    .pipe(imagemin())
    .pipe(gulp.dest(paths.imagemin.dest))
}

// 图片编译
const images = gulp.parallel(imagesTinypng, imagesImagemin)

// 字体编译
function fonts() {
  return gulp
    .src(paths.fonts.src, { base: 'src' })
    .pipe(
      // 一些字体文件是svg，所以也用imagemin处理一下
      imagemin(),
    )
    .pipe(gulp.dest(paths.fonts.dest))
}

// public文件
function statics() {
  return gulp
    .src(paths.public.src, { base: 'src' })
    .pipe(gulp.dest(paths.public.dest))
}

// 合并文件
function merge() {
  return gulp
    .src(paths.useref.src, { base: 'dist' })
    .pipe(useref({
      searchPath: paths.useref.searchPath,
    }))
    .pipe(gulp.dest(paths.useref.dest))
}

// 启动开发服务器的任务
function serve() {
  // 当下面这些文件变化时，自动编译
  gulp.watch(paths.fonts.src, fonts)
  gulp.watch(paths.imagemin.src, imagemin)
  gulp.watch(paths.pages.src, pages)
  gulp.watch(paths.public.src, statics)
  gulp.watch(paths.scripts.src, scripts)
  gulp.watch(paths.styles.src, styles)
  gulp.watch(paths.tinypng.src, tinypng)

  bs.init({
    // 端口，默认就是3000
    port: 3000,
    // 监听目录,文件变化时刷新
    files: 'dist/**',
    server: {
      // 网站根目录
      baseDir: 'dist',

      // 路由，优先级高于网站根目录
      routes: {
        // 临时解决办法，处理html文件中的node_modules引用
        '/node_modules': 'node_modules',
      },
    },
  })
}

// 样式、脚本和模板编译的(并行)组合任务
const compileParallel = gulp.parallel(styles, scripts, pages, images, fonts, statics)

// build任务
const build = gulp.series(clean, compileParallel)

// dev任务
const dev = gulp.series(build, serve)

module.exports = {
  clean,
  styles,
  scripts,
  pages,
  images,
  fonts,
  statics,
  merge,
  compileParallel,
  build,
  dev,
  serve,
}
